package com.dingding.study.service.自定义注解操作数据库;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingding.study.annotation.DataItem;
import com.dingding.study.annotation.Table;
import com.dingding.study.entity.Domain;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: spring-learning
 * @description:
 * @author: liugongding
 * @create: 2021-07-15 16:29
 **/
@Service
@Slf4j
public class AnnotionHandleDB implements InitializingBean {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //public static ThreadLocal<Map<String, String>> dbMap = new ThreadLocal<>();
    //public static ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<>();
    @Autowired
    private CacheLoadingUtil cacheLoadingUtil;

    @Override
    public void afterPropertiesSet() throws Exception {
        handle();
    }

    /**
     * 类加载的时候初始化
     * @return
     * @throws Exception
     */
    public void handle() throws Exception{
        //spring工具类，可以获取指定路径下的全部类
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        // 监听的包
        String basePackage = "com.dingding.study";
        String resourcePattern = "/**/*.class";
        String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                ClassUtils.convertClassNameToResourcePath(basePackage) + resourcePattern;
        try {
            //  获取指定包路径下的类资源
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            List<Domain> domainList= Lists.newArrayList();
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(classname);
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    DataItem filedAnnotation = field.getAnnotation(DataItem.class);
                    if (filedAnnotation != null) {
                        // 获取属性
                        String key = filedAnnotation.key();
                        Domain domain = new Domain();
                        domain.setDataKey(key);
                        domainList.add(domain);
                    }
                }
            }
            List<Domain> handle = handle(domainList);
            if (CollectionUtils.isNotEmpty(handle)) {
                cacheLoadingUtil.loadingData(handle);
            }
            //log.info("全局map的值：{}", dbMap.get());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //dbMap.remove();
        }
    }

    public List<Domain> handle(List<Domain> condition) throws SQLException {
        Class<? extends Domain> aClass = Domain.class;
        Table table = aClass.getAnnotation(Table.class);
        //Column column = aClass.getAnnotation(Column.class);
        String tableValue = table.value();
        List<String> collect = null;
        if (CollectionUtils.isNotEmpty(condition)) {
             collect = condition.stream().map(Domain::getDataKey).collect(Collectors.toList());
        }
//        String columnValue = column.value();
        StringBuilder sb = new StringBuilder();
        sb.append("select " + "* " + "from ").append(tableValue).append(" where 1=1");
        if (CollectionUtils.isNotEmpty(collect)) {
            String str = collect.stream().map(item -> "'"+item+"'").collect(Collectors.joining(","));
            sb.append(" and data_key in (").append(str).append(")");
        }
        log.info("sql:{}", sb);
        return executeJdbc(sb);
    }



    public List<Domain> executeJdbc(StringBuilder sb) throws SQLException {
        List<Domain> list = Lists.newArrayList();
        PreparedStatement pst = null;
        DruidPooledConnection session = getSqlSession();
        ResultSet result = null;
        try {
            pst = session.getConnection().prepareStatement(sb.toString());
            result = pst.executeQuery();
            ResultSetMetaData md = result.getMetaData(); //获得结果集结构信息,元数据
            int columnCount = md.getColumnCount();   //获得列数
            while (result.next()) {
                Map<String, Object> rowData = new HashMap<>();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = md.getColumnName(i);
                    Object object = result.getObject(i);
                    rowData.put(columnName, object);
                }
                String jsonStr = JSON.toJSONString(rowData);
                Domain domain = JSONObject.parseObject(jsonStr, Domain.class);
                list.add(domain);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (pst != null) {
                try {
                    pst.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            session.close();
        }
        return list;
    }



    /**
     * 获取sqlSession
     * @return
     */
    public DruidPooledConnection getSqlSession() throws SQLException {
        DruidDataSource dataSource = (DruidDataSource) jdbcTemplate.getDataSource();
        DruidPooledConnection connection = dataSource.getConnection();
        return connection;
//        return SqlSessionUtils.getSqlSession(sqlSessionTemplate.getSqlSessionFactory(),
//                sqlSessionTemplate.getExecutorType(), sqlSessionTemplate.getPersistenceExceptionTranslator());
    }

    /**
     * 关闭sqlSession
     * @param session
     */
    public void closeSqlSession(SqlSession session){
        session.close();
        //SqlSessionUtils.closeSqlSession(session, sqlSessionTemplate.getSqlSessionFactory());
    }
}
